package pl.vanta.mjuzik.gui.panels;

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Hashtable;

import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import pl.vanta.mjuzik.gui.listeners.IPlayerControllerPanel;
import pl.vanta.mjuzik.gui.listeners.PlayerControllerListener;
import pl.vanta.mjuzik.gui.listeners.PlayerLoadedListener;
import pl.vanta.mjuzik.gui.listeners.PlayerProgressListener;
import pl.vanta.mjuzik.model.AudioFile;
import pl.vanta.utils.gui.panels.VListenerPanel;
import pl.vanta.utils.gui.sliders.VSlider;

public class PlayerControllerPanel extends VListenerPanel<PlayerControllerListener> implements ActionListener, PlayerProgressListener,
		PlayerLoadedListener, ChangeListener, IPlayerControllerPanel
{
	private static final long	serialVersionUID	= 1L;

	private JButton				btnPrevious;
	private JButton				btnPlay;
	private JButton				btnPause;
	private JButton				btnStop;
	private JButton				btnNext;

	private VSlider				positionSlider;
	private VSlider				volumeSlider;
	private VSlider				balanceSlider;

	private boolean				ignoreStateChange;

	public PlayerControllerPanel()
	{
		initComponents();
		setupComponents();
		layoutComponents();
	}

	public void initComponents()
	{
		this.btnPrevious = new JButton("\u25C0\u25C0");
		this.btnPlay = new JButton("\u25B6");
		this.btnPause = new JButton("| |");
		this.btnStop = new JButton("\u25A0");
		this.btnNext = new JButton("\u25B6\u25B6");

		this.positionSlider = new VSlider();
		this.volumeSlider = new VSlider();
		this.balanceSlider = new VSlider();
	}

	public void setupComponents()
	{
		this.btnPrevious.addActionListener(this);
		this.btnPlay.addActionListener(this);
		this.btnPause.addActionListener(this);
		this.btnStop.addActionListener(this);
		this.btnNext.addActionListener(this);

		this.positionSlider.setMinimum(0);
		this.positionSlider.setValue(0);
		this.positionSlider.addChangeListener(this);
		this.positionSlider.setEnabled(false);
		this.positionSlider.setToolTipText("Position");
		this.positionSlider.setPaintLabels(true);

		createPositionSliderLabels();

		this.volumeSlider.setMinimum(0);
		this.volumeSlider.setMaximum(100);
		this.volumeSlider.setValue(50);
		this.volumeSlider.addChangeListener(this);
		this.volumeSlider.setToolTipText("Volume");
		this.volumeSlider.setPaintTicks(true);
		this.volumeSlider.setPaintLabels(true);
		this.volumeSlider.setMinorTickSpacing(5);
		this.volumeSlider.setMajorTickSpacing(20);
		// this.volumeSlider.setSnapToTicks(true);

		createVolumeSliderLabels();

		this.balanceSlider.setMinimum(-100);
		this.balanceSlider.setMaximum(100);
		this.balanceSlider.setValue(0);
		this.balanceSlider.addChangeListener(this);
		this.balanceSlider.setToolTipText("Balance");
		this.balanceSlider.setPaintTicks(true);
		this.balanceSlider.setPaintLabels(true);
		this.balanceSlider.setMinorTickSpacing(5);
		this.balanceSlider.setMajorTickSpacing(10);
		// this.balanceSlider.setSnapToTicks(true);

		createBalanceSliderLabels();
	}

	public void layoutComponents()
	{
		JPanel buttonsPanel = new JPanel();

		buttonsPanel.add(this.btnPrevious);
		buttonsPanel.add(this.btnPlay);
		buttonsPanel.add(this.btnPause);
		buttonsPanel.add(this.btnStop);
		buttonsPanel.add(this.btnNext);

		JPanel slidersPanel = new JPanel();
		slidersPanel.setLayout(new BoxLayout(slidersPanel, BoxLayout.Y_AXIS));
		slidersPanel.add(this.positionSlider);
		slidersPanel.add(this.volumeSlider);
		slidersPanel.add(this.balanceSlider);

		this.setLayout(new BorderLayout());

		this.add(buttonsPanel, BorderLayout.NORTH);
		this.add(slidersPanel, BorderLayout.CENTER);
	}

	@Override
	public void actionPerformed(ActionEvent e)
	{
		if (e.getSource() == this.btnPrevious)
		{
			for (PlayerControllerListener l : this.listeners)
			{
				l.prev();
			}
		}
		else if (e.getSource() == this.btnPlay)
		{
			for (PlayerControllerListener l : this.listeners)
			{
				l.play();
			}
		}
		else if (e.getSource() == this.btnPause)
		{
			for (PlayerControllerListener l : this.listeners)
			{
				l.pause();
			}
		}
		else if (e.getSource() == this.btnStop)
		{
			for (PlayerControllerListener l : this.listeners)
			{
				l.stop();
			}
		}
		else if (e.getSource() == this.btnNext)
		{
			for (PlayerControllerListener l : this.listeners)
			{
				l.next();
			}
		}
	}

	@Override
	public void updateProgress(long milis, float progress, int bytes)
	{
		if (!this.positionSlider.getValueIsAdjusting())
		{
			this.ignoreStateChange = true;

			this.positionSlider.setValue(bytes);

			this.ignoreStateChange = false;
		}
	}

	@Override
	public void playerLoaded(AudioFile audioFile)
	{
		this.positionSlider.setMaximum((int) audioFile.getFile().length());
		this.positionSlider.setEnabled(true);
		this.positionSlider.setValue(0);

		createPositionSliderLabels();
	}

	@Override
	public void playerUnloaded()
	{
		this.positionSlider.setValue(0);
		this.positionSlider.setEnabled(false);
	}

	@Override
	public void stateChanged(ChangeEvent e)
	{
		if (this.volumeSlider.equals(e.getSource()))
		{
			volumeChanged();
		}
		else if (this.balanceSlider.equals(e.getSource()))
		{
			balanceChanged();
		}
		else if (this.positionSlider.equals(e.getSource()))
		{
			positionChanged();
		}
	}

	private void volumeChanged()
	{
		for (PlayerControllerListener listener : this.listeners)
		{
			listener.setVolume(this.volumeSlider.getValue() / 100d);
		}
	}

	private void balanceChanged()
	{
		for (PlayerControllerListener listener : this.listeners)
		{
			listener.setBalance(this.balanceSlider.getValue() / 100d);
		}
	}

	private void positionChanged()
	{
		if (!this.ignoreStateChange && !this.positionSlider.getValueIsAdjusting())
		{
			for (PlayerControllerListener listener : this.listeners)
			{
				listener.setPosition(this.positionSlider.getValue());
			}
		}
	}

	@Override
	public double getBalance()
	{
		return this.balanceSlider.getValue() / 100d;
	}

	@Override
	public double getVolume()
	{
		return this.volumeSlider.getValue() / 100d;
	}

	private void createPositionSliderLabels()
	{
		Hashtable<Integer, JComponent> table = new Hashtable<Integer, JComponent>();

		table.put(0, new JLabel("Start"));
		table.put(new Integer(this.positionSlider.getMaximum()), new JLabel("End"));

		this.positionSlider.setLabelTable(table);
	}

	private void createBalanceSliderLabels()
	{
		Hashtable<Integer, JComponent> table = new Hashtable<Integer, JComponent>();

		table.put(-100, new JLabel("Left"));
		table.put(0, new JLabel("Stereo"));
		table.put(100, new JLabel("Right"));

		this.balanceSlider.setLabelTable(table);
	}

	private void createVolumeSliderLabels()
	{
		Hashtable<Integer, JComponent> table = new Hashtable<Integer, JComponent>();

		table.put(0, new JLabel("Min"));
		table.put(100, new JLabel("Max"));

		this.volumeSlider.setLabelTable(table);
	}
}